/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       new_map_options_dialog.cpp

	$Header: /game/new_map_options_dialog.cpp $

	$NoKeywords: $

 ************************************************************************/


// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "new_map_options_dialog.h"

#include "adaptor_handler.h"
#include "bitmap_layer_window.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_window.h"
#include "bound_handler.h"
#include "button_cache.h"
#include "difficulty_level.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "interface_help.h"
#include "map_header.h"
#include "options.h"
#include "scrollbar.h"
#include "standard_fonts.h"
#include "text_edit_window.h"
#include "toggle_button.h"
#include "town_properties.h"

extern t_button_cache g_large_button;
extern t_button_cache g_checkbox;
extern t_bitmap_group_cache g_banners_55;
extern t_bitmap_group_cache g_difficulty_60_icons;
extern t_bitmap_group_cache  g_difficulty_icons;
extern t_bitmap_group_cache  g_banners_38( "icons.flags.38" );
static t_bitmap_group_cache  g_color_arrows( "button.arrows" );

extern t_external_string const k_text_guards_move;
extern t_external_string const k_text_guards_dont_move;
extern t_external_string const k_text_back_button( "back.shared" );

const int k_millisecond_count = 1000;
const int k_minute_count = k_millisecond_count * 60;
const int k_interval_count = k_minute_count;

static int const k_turn_lengths[] = 
{ 
    1 * k_interval_count,
    2 * k_interval_count,
    4 * k_interval_count,
    6 * k_interval_count,
    8 * k_interval_count,
    10 * k_interval_count,
    15 * k_interval_count,
    20 * k_interval_count,
    25 * k_interval_count,
    30 * k_interval_count,
    0 
};


static t_external_string k_text_turn_length_1( "new_map_turn_length_1.misc");
static t_external_string k_text_turn_length_2( "new_map_turn_length_2.misc");
static t_external_string k_text_turn_length_3( "new_map_turn_length_3.misc");
static t_external_string k_text_turn_length_4( "new_map_turn_length_4.misc");
static t_external_string k_text_turn_length_5( "new_map_turn_length_5.misc");
static t_external_string k_text_turn_length_6( "new_map_turn_length_6.misc");
static t_external_string k_text_turn_length_7( "new_map_turn_length_7.misc");
static t_external_string k_text_turn_length_8( "new_map_turn_length_8.misc");
static t_external_string k_text_turn_length_9( "new_map_turn_length_9.misc");
static t_external_string k_text_turn_length_10( "new_map_turn_length_10.misc");
static t_external_string k_text_turn_length_11( "new_map_turn_length_11.misc");

static t_external_string const k_text_turn_lengths[] = 
{ 
    k_text_turn_length_1,
    k_text_turn_length_2,
    k_text_turn_length_3,
    k_text_turn_length_4,
    k_text_turn_length_5,
    k_text_turn_length_6,
    k_text_turn_length_7,
    k_text_turn_length_8,
    k_text_turn_length_9,
    k_text_turn_length_10,
    k_text_turn_length_11
};

static t_bitmap_group_cache const	k_flags( "icons.flags.16" );

static t_bitmap_group_cache const k_dialog_bitmaps("dialog.new_game_options");
static t_external_string const k_text_human_player( "Player.new_game" );
extern t_external_string const k_text_cancel;
extern t_external_string const k_text_begin( "begin" );
extern t_external_string const k_text_play_this_map;

t_new_map_options_dialog::t_new_map_options_dialog( t_window* parent, t_map_header const& header ) 
						: t_window( k_completely_transparent, parent ),
						  m_map_header( header )
{
	t_screen_rect rect;
	t_screen_rect parent_rect;
	int			  i;
	t_help_block const&		shared_help = get_help_block( "shared" );
	t_help_block const&		help = get_help_block( "file_open" );

	// Initialize default values
	for (i = 0; i < k_active_player_color_count; i++)
		m_setup[i].human = false;
	m_player_names.push_back( k_text_human_player );
	parent_rect = parent->get_client_rect();
	m_bitmaps = k_dialog_bitmaps.get();
	m_difficulty = k_difficulty_normal; // Default;

	// center rect in parent window
	rect = m_bitmaps->get_rect();
	rect += t_screen_point( (parent_rect.width() - rect.width() ) / 2,
		                    (parent_rect.height() - rect.height() ) / 2 );
	rect.right += 5;
	rect.bottom += 5;

	// add background
	m_background = new t_bitmap_layer_window( m_bitmaps->find( "background" ), 
		                                      t_screen_point(0,0), this);
	m_background->set_drop_shadow( true );

	// add cancel button
	t_button* button;

	t_help_block const&		back_help = get_help_block( "scenario_information" );
	button = new t_button( g_large_button.get(), find_location( "back_button"), m_background,
		                   k_text_back_button );
	button->set_click_handler( bound_handler( *this, &t_new_map_options_dialog::cancel ) );
	set_help( button, back_help, "close" );	
	
	// add begin button
	m_begin_button = new t_button( g_large_button.get(), find_location( "begin_button"),
		                           m_background, k_text_begin );
	m_begin_button->set_click_handler( bound_handler( *this, &t_new_map_options_dialog::begin ) );
	set_help( m_begin_button, help, "begin" );
	//m_begin_button->set_help_balloon_text( k_text_play_this_map );

	create_controls();
	set_controls();

	init( rect );
}

// ------------------------------------------------
// dialog to select a new map.
// find location to place a control
// ------------------------------------------------
t_screen_point t_new_map_options_dialog::find_location( std::string const& layer_name ) const
{
	t_bitmap_layer const* layer = m_bitmaps->find( layer_name.c_str() );

	return layer->get_rect().top_left();
}

int t_new_map_options_dialog::get_turn_duration() const
{
	return k_turn_lengths[m_turn_duration_index];
}

// ------------------------------------------------------
// set a position as human or computer
// ------------------------------------------------------
extern t_external_string const k_text_computer_player( "Computer.new_game" );

void t_new_map_options_dialog::set_human( int row, bool human )
{
	t_player_setup& setup = m_setup[row];

	if (setup.human == human)
		return;

	t_player_setup_controls& controls = m_setup_controls[row];

	setup.human = human;
	controls.name->enable( human );
	controls.human->set_pressed( human );
	controls.color_decrease->enable( human && m_map_header.humans > 1 );
	controls.color_increase->enable( human && m_map_header.humans > 1 );

	if (setup.human)
	{
		if (m_player_names.empty())
		{
			int player_count = 0;
			int i;
			for (i = 0; i < m_map_header.players; i++)
			{
				if (m_setup[i].human)
					player_count++;
			}
			setup.name = k_text_human_player.get() + format_string( " %i", player_count );
		}
		else
		{
			setup.name = m_player_names.back();
			m_player_names.pop_back();
		}
	}
	else
	{
		m_player_names.push_back( controls.name->get_text() );
		setup.name = k_text_computer_player;
	}
	controls.name->set_text( setup.name );
}

// ------------------------------------------------------
// respond to a human check / uncheck
// ------------------------------------------------------
void t_new_map_options_dialog::human_checkbox_click( t_button* button, int row )
{
	t_player_setup& setup = m_setup[row];

	if (button->is_pressed() == setup.human)
		return;

	t_player_setup_controls& controls = m_setup_controls[row];

	set_human( row, button->is_pressed() );

	int i;
	for (i = 0; i < m_map_header.players; i++)
	{
		if (m_setup[i].human)
			return;
	}
	for (i = 0; i < m_map_header.players; i++)
	{
		row = (row + 1) % m_map_header.players;
		if (m_map_header.can_be_human[m_setup[row].color])
			break;
	}
	set_human( row, true );
}

// ------------------------------------------------------
// change a position's color
// ------------------------------------------------------
void t_new_map_options_dialog::set_color( int row, t_player_color color )
{
	int team_id = m_map_header.team_id[color];

	team_id = m_team_id_map[team_id];
	m_setup[row].color = color;
	m_setup_controls[row].color->set_frame( k_player_color_keyword[color] );
	m_setup_controls[row].team_window->set_frame( k_player_color_keyword[color] );
	m_setup_controls[row].team_id_window->set_frame( format_string( "team_%d", team_id + 1 ) );

 	t_bitmap_layer const*   image;
	t_color_button_images*  button_images;
	t_player_setup_controls& controls = m_setup_controls[row];
    std::string             name;

    name = k_player_color_keyword[color];
	button_images = &controls.up_color_images;

    image = m_arrow_bitmaps->find( name + "_up_released" );
    button_images->released_image_window->set_bitmap( image );
    image = m_arrow_bitmaps->find( name + "_up_pressed" );
    button_images->pressed_image_window->set_bitmap( image );
    image = m_arrow_bitmaps->find( name + "_up_highlighted" );
    button_images->highlighted_image_window->set_bitmap( image );

	button_images = &controls.down_color_images;

    image = m_arrow_bitmaps->find( name + "_down_released" );
    button_images->released_image_window->set_bitmap( image );
    image = m_arrow_bitmaps->find( name + "_down_pressed" );
    button_images->pressed_image_window->set_bitmap( image );
    image = m_arrow_bitmaps->find( name + "_down_highlighted" );
    button_images->highlighted_image_window->set_bitmap( image );
}

static t_external_string const k_text_random_alignment( "new_map_random_alignment.misc" );

void t_new_map_options_dialog::set_alignment( int row, t_town_type alignment )
{
	std::string text;
	t_bitmap_group_window* window = m_setup_controls[row].alignment;

	if (alignment == k_town_none)
    {
	    window->set_frame( "random" );
		text = k_text_random_alignment;
    }
	else
	{
		window->set_frame( k_town_keyword[alignment] );
		text = get_alignment_name( alignment );
	}
	m_setup[row].alignment = alignment;
	window->set_help_balloon_text( text );
	window->set_right_click_text( text );
}

extern t_external_string const k_difficult_balloon_help[] =
{
	t_external_string( "new_map_difficulty_balloon_help_easy.misc" ),
	t_external_string( "new_map_difficulty_balloon_help_normal.misc" ),
	t_external_string( "new_map_difficulty_balloon_help_hard.misc" ),
	t_external_string( "new_map_difficulty_balloon_help_expert.misc" ),
	t_external_string( "new_map_difficulty_balloon_help_impossible.misc" )
};

extern t_external_string const k_difficulty_help[] =
{
	t_external_string( "new_map_difficulty_help_easy.misc" ),      
	t_external_string( "new_map_difficulty_help_normal.misc" ),    
	t_external_string( "new_map_difficulty_help_hard.misc" ),      
	t_external_string( "new_map_difficulty_help_expert.misc" ),    
	t_external_string( "new_map_difficulty_help_impossible.misc" ) 
};

void t_new_map_options_dialog::set_difficulty( t_difficulty difficulty )
{
	m_difficulty = difficulty;
	m_difficulty_icon->set_frame( k_difficulty_icon_names[ m_difficulty ] );
	m_difficulty_icon->set_help_balloon_text( k_difficult_balloon_help[ difficulty ] );
	m_difficulty_icon->set_right_click_text( k_difficulty_help[ difficulty ] );
	m_difficulty_title->set_text( k_difficult_balloon_help[difficulty] );

	if( m_difficulty == k_difficulty_easy )
		m_difficulty_left_button->enable( false );
	else
		m_difficulty_left_button->enable( true );

	if( m_difficulty == k_difficulty_impossible )
		m_difficulty_right_button->enable( false );
	else
		m_difficulty_right_button->enable( true );
}

void t_new_map_options_dialog::options_increase_difficulty( t_button* button )
{
	enum_incr( m_difficulty );
	if( m_difficulty >= k_difficulty_count )
		m_difficulty = k_difficulty_impossible; 

	set_difficulty( m_difficulty );
}
        
void t_new_map_options_dialog::options_decrease_difficulty( t_button* button )
{
	enum_decr( m_difficulty );
	if( m_difficulty < 0 )
		m_difficulty = k_difficulty_easy; 

	set_difficulty( m_difficulty );
}
        
void t_new_map_options_dialog::change_alignment( t_button* button, int position, int delta )
{
	t_player_setup& setup = m_setup[position];

    t_town_type		alignment = setup.alignment;
	t_player_color	color = setup.color;

	do
	{
		alignment = t_town_type(alignment + delta);
		if (alignment >= k_town_type_count)
	        alignment = k_town_none;
		if (alignment < k_town_none)
			alignment = t_town_type(k_town_type_count - 1);
	} while (alignment != k_town_none && alignment != setup.alignment 
			 && !m_map_header.available_alignments[color][alignment]);

    set_alignment( position, alignment );
}
        
// ------------------------------------------------------
// respond to a color change request
// ------------------------------------------------------
void t_new_map_options_dialog::change_color( t_button* button, int position, int delta )
{
	int                 i;
	t_player_setup&     setup = m_setup[position];
	t_player_color      color = setup.color;

	for (i = 0; i < k_active_player_color_count; i++)
	{
		color = t_player_color( (color + delta + k_active_player_color_count) 
			                    % k_active_player_color_count );
		if (m_map_header.can_be_human[color])
			break;
	}
	// find position using this color
	for (i = 0; i < m_map_header.players; i++)
		if (m_setup[i].color == color)
			break;

    // Swap colors.
	t_town_type alignment = m_setup[i].alignment;

	set_color( i, setup.color );
	set_alignment( i, setup.alignment );
	set_color( position, color );
	set_alignment( position, alignment );
}

namespace
{
	class t_compare_setups
	{
	public:
		t_compare_setups( t_map_header const& header );

		bool operator()( t_player_setup const& left, t_player_setup const& right ) const;
	private:
		t_map_header const& m_map_header;
	};

	inline t_compare_setups::t_compare_setups( t_map_header const& header )
						   : m_map_header( header )
	{
	}
};

static bool has_human_members( t_map_header const& header, int team_id )
{
	t_player_color color;

	for (color = t_player_color(0); color < k_player_color_count; enum_incr( color ))
	{
		if (header.playable[color] && header.can_be_human[color] 
			&& header.team_id[color] == team_id)
			return true;
	}
	return false;
}

static t_player_color get_first_color( t_map_header const& header, int team_id )
{
	t_player_color color;

	for (color = t_player_color(0); color < k_player_color_count; enum_incr( color ))
	{
		if (header.playable[color] && header.team_id[color] == team_id)
			return color;
	}
	return color;
}

bool t_compare_setups::operator ()( t_player_setup const& left, t_player_setup const& right ) const
{
	t_player_color	left_color = left.color;
	t_player_color	right_color = right.color;
	int				left_team = m_map_header.team_id[left_color];
	int				right_team = m_map_header.team_id[right_color];

	// sort first based on teams.
	if (left_team != right_team)
	{
		// if one side has humans, that's first.
		if (has_human_members( m_map_header, left_team ))
		{
			if (!has_human_members( m_map_header, right_team ))
				return true;
		}
		else if (has_human_members( m_map_header, right_team ))
			return false;
		// otherwise, sort by the color of the first member.
		return get_first_color( m_map_header, left_team ) 
			 < get_first_color( m_map_header, right_team );
	}
	// within a team, show humans first.
	if (m_map_header.can_be_human[left_color] && !m_map_header.can_be_human[right_color])
		return true;
	if (!m_map_header.can_be_human[left_color] && m_map_header.can_be_human[right_color])
		return false;
	// finally, sort by color.
	return left_color < right_color;
}


static t_external_string const k_text_win_condition_title( "new_map_win_condition.misc" );
static t_external_string const k_text_loss_condition_title( "new_map_loss_condition.misc" );


void t_new_map_options_dialog::set_controls()
{
	// setup options controls
	std::string		text;

	m_scenario_description->set_text( m_map_header.description );
    
    text = k_text_loss_condition_title;
    text += m_map_header.loss_condition;
	text += "\n\n";
	text += k_text_win_condition_title;
    text += m_map_header.victory_condition;
	m_end_condition->set_text( text );

	// create the player colors
	int				player_count = 0;
	t_player_color	color;

	for (color = t_player_color(0); color < k_active_player_color_count; enum_incr(color))
	{
		if (!m_map_header.playable[color])
			continue;
		m_setup[player_count].color = color;
		++player_count;
	}
	// sort them by team, then by human playable, then by color.
	std::sort( m_setup, m_setup + player_count, t_compare_setups( m_map_header ) );

	// create the mapping of internal team id's to displayed team id's
	int		team_count = 0;
	int		player;
	int		team_id;

	for (team_id = 0; team_id < k_active_player_color_count; ++team_id)
		m_team_id_map[team_id] = -1;
	for (player = 0; player < player_count; ++player)
	{
		color = m_setup[player].color;
		team_id = m_map_header.team_id[color];
		if (m_team_id_map[team_id] < 0)
			m_team_id_map[team_id] = team_count++;
	}

	for (player = 0; player < player_count; ++player)
	{
        // Setup options.
		t_player_setup&			 setup = m_setup[player];
		t_player_setup_controls& controls = m_setup_controls[player];

		color = setup.color;
		set_color( player, color );
		setup.alignment = k_town_none;
		if (m_map_header.can_be_human[color] && !m_player_names.empty())
		{
			setup.human = true;
			
			if (!m_player_names.empty()) {
				setup.name = m_player_names.back();
				m_player_names.pop_back();
			} else {
				setup.name = k_text_human_player.get() + format_string( " %i", player );
			}
		}
		else
		{
			setup.human = false;
			setup.name = k_text_computer_player;
		}
		// if legal alignmens == 1, use that alignment.  Otherwise, display random.
		if (m_map_header.available_alignments[color].count() == 1)
		{
			for (setup.alignment = t_town_type(0); setup.alignment < k_town_type_count;
				 enum_incr( setup.alignment ))
				if (m_map_header.available_alignments[color][setup.alignment])
					break;
			controls.alignment_decrease->enable( false );
			controls.alignment_increase->enable( false );
		}

		// setup controls
		controls.name->set_text( setup.name );

		controls.name->enable( setup.human );

        // Control for changing colors.
		controls.color_increase->enable( setup.human && m_map_header.humans > 1 );
		controls.color_decrease->enable( setup.human && m_map_header.humans > 1 );
		controls.human->set_pressed( setup.human );
		controls.human->enable( m_map_header.can_be_human[color] );
		controls.human->set_visible( m_map_header.can_be_human[color] );
		controls.window->set_visible( true );
        set_alignment( player, setup.alignment );
	}
	while (player < k_active_player_color_count)
	{
		m_setup[player].human = false;
		m_setup_controls[player].window->set_visible( false );
		player++;
	}
}

// ------------------------------------------------
// dialog to select a new map.
// begin game
// ------------------------------------------------
void t_new_map_options_dialog::begin( t_button* )
{
	// Store the players' chosen names
	for (int player = 0; player < k_active_player_color_count; player++)
	{
		m_setup[player].name = m_setup_controls[player].name->get_text();
	}

	set_guard_move_preference( m_guards_move );

	m_return_value = 1;
	close();
}

// ------------------------------------------------
// dialog to select a new map.
// cancel dialog
// ------------------------------------------------
void t_new_map_options_dialog::cancel( t_button* )
{
	m_return_value = 0;
	close();
}

void t_new_map_options_dialog::turn_duration_scrollbar_move ( t_scrollbar* scrollbar, int value )
{
	m_turn_duration_index = value;
	m_turn_duration_text->set_text ( k_text_turn_lengths[value] );
}

// Create color button for changing colors.
static t_button* create_color_button( t_screen_point			origin, 
									  t_window*					parent, 
									  std::string				direction_name,
									  t_bitmap_group_ptr		arrow_bitmaps,
									  t_color_button_images*	button_images )
{
	t_button*               button;
	t_bitmap_layer const*   released_image;
	t_bitmap_layer const*   pressed_image;
	t_bitmap_layer const*   highlighted_image;
	t_bitmap_layer const*   disabled_image;
	t_screen_point          button_origin;
	t_screen_point          button_location;
	t_screen_point          offset;

    released_image = arrow_bitmaps->find( direction_name + "_released" );
    pressed_image = arrow_bitmaps->find( direction_name + "_pressed" );
    highlighted_image = arrow_bitmaps->find( direction_name + "_highlighted" );
    disabled_image = arrow_bitmaps->find( direction_name + "_disabled" );
	
    // Local up/down coords.
	button_origin = released_image->get_rect().top_left();

    // Origin is offset within parent.
	button_location = button_origin + origin;

	button = new t_button( button_location, parent );
	
	button_images->released_image_window = new t_bitmap_layer_window( released_image, //t_bitmap_layer_ptr(),
	                                -button_origin, button );
	button_images->pressed_image_window = new t_bitmap_layer_window( pressed_image, //t_bitmap_layer_ptr(),
	                                -button_origin, button );
	button_images->highlighted_image_window = new t_bitmap_layer_window( highlighted_image, //t_bitmap_layer_ptr(),
	                                -button_origin, button );
	button_images->disabled_image_window = new t_bitmap_layer_window( disabled_image, //t_bitmap_layer_ptr(),
	                                -button_origin, button );


    button->set_released_image( button_images->released_image_window );
    button->set_pressed_image( button_images->pressed_image_window );
    button->set_highlighted_image( button_images->highlighted_image_window );
    button->set_disabled_image( button_images->disabled_image_window );

    return button;
}

//static t_external_string const k_text_guards_pressed( "new_map_guards_pressed.misc" );
//static t_external_string const k_text_guards_released( "new_map_guards_released.misc" );

void t_new_map_options_dialog::guard_clicked( t_button* button )
{
	t_help_block const&		shared_help = get_help_block( "shared" );
	m_guards_move = button->is_pressed();
	if (m_guards_move)
	{
		m_guards_can_move_window->set_text( k_text_guards_move );
		set_help( button, shared_help, "guards_pressed" );
	} else
	{
		m_guards_can_move_window->set_text( k_text_guards_dont_move );
		set_help( button, shared_help, "guards_released" );
	}
}

// ------------------------------------------------
// dialog to select a new map.
// create the controls for player setup options
// -------------------------------------------------
static t_external_string const k_text_name( "Name.new_game");
static t_external_string const k_text_human( "Human.new_game" );
static t_external_string const k_text_color( "Color.new_game" );
static t_external_string const k_text_team( "new_map_team.misc" ); //Color.new_game" );
static t_external_string const k_text_difficulty( "new_map_difficulty.misc" );
static t_external_string const k_text_alignment( "Alignment.new_game" );
//static t_external_string const k_text_guards_move( "new_map_guards_move.misc" );


void t_new_map_options_dialog::create_controls()
{
	t_screen_point origin = -m_background->get_screen_rect().top_left();

	t_help_block const&		shared_help = get_help_block( "shared" );
	t_help_block const&		help = get_help_block( "file_open" );

	// create titles
	t_bitmap_layer const* layer;
	t_window_ptr   window_ptr;
	t_text_window* text_window;
	t_screen_rect  rect;
	t_screen_point offset;

	rect = m_bitmaps->find( "name_title" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, m_background,
		                             k_text_name, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	text_window->set_center_horizontal();

	rect = m_bitmaps->find( "team_title" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, m_background,
		                             k_text_team, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	text_window->set_center_horizontal();

	rect = m_bitmaps->find( "alignment_title" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, m_background,
		                             k_text_alignment, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	text_window->set_center_horizontal();

	rect = m_bitmaps->find( "color_title" )->get_rect() + origin;
	text_window = new t_text_window( get_font( rect.height() ), rect, m_background,
		                             k_text_color, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	text_window->set_center_horizontal();

	rect = m_bitmaps->find( "difficulty_text" )->get_rect() + origin;
	m_difficulty_title = new t_text_window( get_font( rect.height() / 2 ), rect, m_background,
		                             k_text_difficulty, t_pixel_24(0,0,0) );
	m_difficulty_title->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_difficulty_title->set_center_horizontal();
	m_difficulty_title->set_center_vertical();

    // Map description.
	rect = m_bitmaps->find( "map_description" )->get_rect() + origin;
	m_scenario_description = new t_text_window( get_font( 18 ), rect, m_background,
		                             "", t_pixel_24(0,0,0) );
	m_scenario_description->set_drop_shadow( true, t_pixel_24(200,200,200) );
    
	rect = m_bitmaps->find( "victory_loss_condition" )->get_rect() + origin;
	m_end_condition = new t_text_window( get_font( 18 ), rect, m_background,
		                             "", t_pixel_24(0,0,0) );
	m_end_condition->set_drop_shadow( true, t_pixel_24(200,200,200) ); 
  
	std::string     name;
	std::string     text;
    
    // Turn duration.
	m_turn_duration_index = ELEMENTS_OF( k_text_turn_lengths ) - 1;

/* This has been delayed until later!

	layer = m_bitmaps->find( "turn_duration_text_banner" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_background );

    // Turn duration text.
	text = k_text_turn_lengths[ELEMENTS_OF( k_text_turn_lengths ) - 1];
    rect = m_bitmaps->find( "turn_duration" )->get_rect();
	m_turn_duration_text = new t_text_window( get_font(rect.height()), rect+origin, m_background, 
											  text, t_pixel_24(0,0,0) );
	m_turn_duration_text->set_center_horizontal();

    // Turn duration scrollbar.
    rect = m_bitmaps->find( "turn_duration_scrollbar" )->get_rect();
	m_turn_duration_scrollbar = new t_scrollbar( rect.top_left()+origin, rect.width(),
												 m_background, 0, 
												 ELEMENTS_OF( k_text_turn_lengths ) - 1, 
												 false );
	m_turn_duration_scrollbar->set_handler( bound_handler( *this, 
					&t_new_map_options_dialog::turn_duration_scrollbar_move ));
	m_turn_duration_scrollbar->set_position( ELEMENTS_OF( k_text_turn_lengths ) - 1 );
	set_help ( m_turn_duration_scrollbar, help, "turn_duration");
*/

	// create top bar
	t_window*			  window;
	int					  i;
	t_screen_point		  point;

	layer = m_bitmaps->find( "player_box_top" );
	window = new t_bitmap_layer_window( layer, origin, m_background );

	layer = m_bitmaps->find( "player_difficulty_box" );
	m_player_difficulty_box = new t_bitmap_layer_window( layer, origin, m_background );

    point = m_bitmaps->find("player_difficulty")->get_rect().top_left()
		- layer->get_rect().top_left();

	t_bitmap_group_ptr      difficulty_60 = g_difficulty_60_icons.get();
	m_difficulty_icon = new t_bitmap_group_window( difficulty_60, point, 0,
									m_player_difficulty_box );
	set_help ( m_difficulty_icon, help, "player_difficulty");

	t_toggle_button* toggle_button;
	t_button_handler	handler;

	m_guards_move = get_guard_move_preference();
	toggle_button = new t_toggle_button( find_location( "creature_guard_released" ), m_background );
	set_button_layers( toggle_button, m_bitmaps, "creature_guard" );
	toggle_button->set_pressed( m_guards_move );
	if (m_guards_move)
		set_help( toggle_button, shared_help, "guards_pressed" );
		//toggle_button->set_help_balloon_text( k_text_guards_pressed );
	else
		set_help( toggle_button, shared_help, "guards_released" );
//		toggle_button->set_help_balloon_text( k_text_guards_released );

	handler = bound_handler( *this, &t_new_map_options_dialog::guard_clicked );
	toggle_button->set_click_handler( handler );

	// add a text description for guards
	rect = m_bitmaps->find( "creature_guard_text" )->get_rect() + origin;
	m_guards_can_move_window = new t_text_window( get_font( rect.height() / 2 ), rect, m_background,
									 "", t_pixel_24(0,0,0) );
	m_guards_can_move_window->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_guards_can_move_window->set_center_horizontal();
	if (m_guards_move)
		m_guards_can_move_window->set_text( k_text_guards_move );
	else
		m_guards_can_move_window->set_text( k_text_guards_dont_move );

    // Buttons for difficulty.
	t_help_block const&		campaign_help = get_help_block( "campaign" );
    m_difficulty_left_button = create_button( m_bitmaps, "left", m_background, -offset );
    m_difficulty_left_button->set_click_handler ( bound_handler( *this, &t_new_map_options_dialog::options_decrease_difficulty ) );
	set_help( m_difficulty_left_button, campaign_help, "player_difficulty_left" );

    m_difficulty_right_button = create_button( m_bitmaps, "right", m_background, -offset );
    m_difficulty_right_button->set_click_handler ( bound_handler( *this, &t_new_map_options_dialog::options_increase_difficulty ) );
	set_help( m_difficulty_right_button, campaign_help, "player_difficulty_right" );

	// create items
	//t_bitmap_layer const*	box_left;
	//t_bitmap_layer const*	box_right;
	//t_bitmap_layer const*	box_bottom;
	t_bitmap_layer *	    player_bg_ptr;
	t_screen_rect			name_rect;
	t_screen_rect			human_rect;
	t_screen_rect			color_arrow_rect;
	t_screen_rect			color_rect;
	t_screen_point			player_background_point;
	t_screen_rect			alignment_rect;
	t_screen_rect			alignment_arrow_rect;
	t_screen_rect			team_rect;
	t_screen_point			alignment_down_point;
	t_screen_point			alignment_up_point;
	t_screen_point			left_arrow_point;
	t_screen_rect			line_rect;
	t_screen_point			line_origin;
	t_screen_point			right_arrow_point;
	t_bitmap_group_ptr      banners;
	t_bitmap_group_ptr      banners_55;

	line_origin		= m_bitmaps->find( "player_1" )->get_rect().top_left() + origin;

	name_rect		= m_bitmaps->find( "player_name" )->get_rect() - line_origin + origin;
	human_rect		= m_bitmaps->find( "human_checkbox" )->get_rect() - line_origin + origin;
    //human_rect      -= name_rect.top_left();

	player_background_point = -line_origin + origin;
	player_bg_ptr = m_bitmaps->find( "player_background" );

	color_rect = m_bitmaps->find( "player_flag" )->get_rect() - line_origin + origin;
	color_arrow_rect =  m_bitmaps->find( "color_arrows" )->get_rect() - line_origin + origin;
	alignment_arrow_rect =  m_bitmaps->find( "alignment_arrows" )->get_rect() - line_origin + origin;
	team_rect		    = m_bitmaps->find( "team_flag" )->get_rect() - line_origin + origin;

	banners				= g_banners_38.get();
	banners_55			= g_banners_55.get();

	m_arrow_bitmaps = g_color_arrows.get();
	for (i = 0; i < k_active_player_color_count; i++)
	{
		t_player_setup_controls& controls = m_setup_controls[i];

		name = format_string( "player_%d", i + 1 );
	    rect = m_bitmaps->find( name )->get_rect();
	    line_rect = m_bitmaps->find( name )->get_rect() + origin;

		controls.window = new t_window( line_rect, k_completely_transparent,
			                            m_background );
		controls.window->set_visible( false );

		controls.alignment_increase = create_button( m_arrow_bitmaps, "alignment_up",
													 controls.window, 
													 -alignment_arrow_rect.top_left() );
        handler = add_2nd_argument( add_2nd_argument( bound_handler( *this,
			                        &t_new_map_options_dialog::change_alignment ), i ), -1 );
		controls.alignment_increase->set_click_handler( handler );
	    set_help ( controls.alignment_increase, help, "alignment");
		
        controls.alignment_decrease = create_button( m_arrow_bitmaps, "alignment_down", 
													 controls.window, 
													 -alignment_arrow_rect.top_left() );
        handler = add_2nd_argument( add_2nd_argument( bound_handler( *this,
			                        &t_new_map_options_dialog::change_alignment ), i ), 1 );
		controls.alignment_decrease->set_click_handler( handler );
	    set_help ( controls.alignment_decrease, help, "alignment");

		controls.color = new t_bitmap_group_window( banners, color_rect.top_left(), 0,
			                                        controls.window );
	    set_help ( controls.color, help, "player_color_banner");
		controls.alignment = new t_bitmap_group_window( banners, t_screen_point(0,0), 0, controls.color );
	    set_help ( controls.alignment, help, "alignment_banner");

        handler = add_2nd_argument( add_2nd_argument( bound_handler( *this,
			                        &t_new_map_options_dialog::change_color ), i ), -1 );
		controls.color_decrease = create_color_button( color_arrow_rect.top_left(),
													   controls.window,
													   "purple_up", m_arrow_bitmaps,
													   &controls.up_color_images );
		controls.color_decrease->set_click_handler( handler );
	    set_help ( controls.color_decrease, help, "player_color");
		
        handler = add_2nd_argument( add_2nd_argument( bound_handler( *this,
			                        &t_new_map_options_dialog::change_color ), i ), 1 );
		controls.color_increase = create_color_button( color_arrow_rect.top_left(), 
													   controls.window, "purple_down", 
													   m_arrow_bitmaps,
													   &controls.down_color_images );
		controls.color_increase->set_click_handler( handler );
	    set_help ( controls.color_increase, help, "player_color");

        // Team number (ID).
		controls.team_window = new t_bitmap_group_window( banners, team_rect.top_left(), 0, controls.window );
		controls.team_id_window = new t_bitmap_group_window( banners, t_screen_point(0,0), 0, controls.team_window );
	    set_help ( controls.team_window, help, "team_id");

        // Player name.
		controls.name_background = new t_bitmap_layer_window( player_bg_ptr, player_background_point,
                                            controls.window );

		controls.name = new t_text_edit_window( get_font( name_rect.height() ), name_rect,
										   controls.window, "", t_pixel_24(0,0,0) );
		controls.name->set_drop_shadow( true, t_pixel_24(200,200,200) );
	    set_help ( controls.name, help, "player_name");
        
        // Human or not.
		controls.human = new t_toggle_button( g_checkbox.get(), human_rect.top_left(),
			                                  controls.window ); //controls.name ); //
		handler = add_2nd_argument( bound_handler( *this, 
			                        &t_new_map_options_dialog::human_checkbox_click ), i );
		controls.human->set_click_handler( handler );

		point.y += line_rect.height();
	}
	set_difficulty( m_difficulty );
}

